/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年8月22日
 */
package com.massyframework.beanskin.runtime.service.instrument;

import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.lang.reflect.Method;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.massyframework.beanskin.framework.FrameworkDestroyingEvent;
import com.massyframework.beanskin.framework.FrameworkEventAdapter;

/**
 * 虚拟机助手服务工厂
 * @author huangkh
 *
 */
public class VirtualMachineHelper extends FrameworkEventAdapter{
	private final String VM_CLASSNAME = "com.sun.tools.attach.VirtualMachine";

    private Logger logger = LoggerFactory.getLogger(VirtualMachineHelper.class);
    private Class<?> clazz;
    private Object vm;
	    
	/**
	 * 
	 */
	public VirtualMachineHelper() {
		RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();
        String pid = runtime.getName();
        if (pid.indexOf("@") != -1)
            pid = pid.substring(0, pid.indexOf("@"));

        ClassLoader classLoader = this.getClass().getClassLoader();
        try {
        	this.clazz = classLoader.loadClass(VM_CLASSNAME);
            Method method = this.clazz.getMethod("attach", new Class[]{String.class});
            this.vm = method.invoke(this.clazz, new Object[]{pid});
        }catch(Throwable e){
            if (logger.isErrorEnabled()){
                logger.error(e.getMessage(), e);
            }
        }
	}
	
	protected Class<?> getVirutalMachineClass(){
		return this.clazz;
	}
	
	/**
	 * 附加
	 * @param path
	 */
	public void attach(String path) {
		if (this.vm != null){
            try{
                // now deploy the actual agent, which will wind up calling agentmain()
                Method loadAgentMethod = this.clazz.getMethod("loadAgent", new Class[] { String.class, String.class });
                if (loadAgentMethod != null){
                    loadAgentMethod.invoke(this.vm, new Object[] {path, null});

                    if (logger.isDebugEnabled()) {
                        logger.debug(String.format("attach %s success.", path));
                    }
                }
            }catch(Throwable e){
                if (logger.isErrorEnabled()){
                    logger.error(e.getMessage(), e);
                }
            }
        }

	}

	
	/**
	 * 解除附加
	 */
	protected void detach() {
		if (this.vm != null){
            try{
                // now deploy the actual agent, which will wind up calling agentmain()
                Method loadAgentMethod = this.clazz.getMethod("detach", new Class[0]);
                if (loadAgentMethod != null){
                    loadAgentMethod.invoke(this.clazz, new Object[0]);

                    if (logger.isDebugEnabled()) {
                        logger.debug("detach success.");
                    }
                }
            }catch(Throwable e){
                if (logger.isErrorEnabled()){
                    logger.error(e.getMessage(), e);
                }
            }
        }
	}

	@Override
	public void onEvent(FrameworkDestroyingEvent event) {
		this.detach();
	}

	
}
